const constant = require('./constant');

const dbHash = {};

[
  constant.GAMEDB_NAME,
  constant.BCEVENTDB_NAME,
  constant.BCNFTDB_NAME
].forEach(
  (item) => {
    dbHash[item] = {
      'lockTimes': 0,
      'conn': null
    };
  }
);

async function internalCreateConn(app, name) {
  if (!dbHash.hasOwnProperty(name)) {
    throw new Error('dbpool error dbname:' + name);
  }
  const dbObj = dbHash[name];
  while (dbObj.lockTimes > 0) {
    await new Promise(function (resolve, reject) {
      setTimeout(function () {
        resolve();
      }, 1000);
    });
  }
  if (!dbObj.conn) {
    ++dbObj.lockTimes;
    try {
      const {err, conn} = await app.getDbConn(name);
      if (err) {
        throw new Error('getGBcEventConn error:' + err);
      }
      dbObj.conn = conn;
    } finally {
      --dbObj.lockTimes;
    }
  }
  return dbObj.conn;
}

async function reconnectDb(app, name, conn) {
  try {
    if (!dbHash.hasOwnProperty(name)) {
      throw new Error('reconnectDb dbpool error dbname:' + name);
    }
    conn.release();
    const dbObj = dbHash[name];
    try {
      const {err, conn} = await app.getDbConn(name);
      if (err) {
        throw new Error('reconnectDb getGBcEventConn error:' + err);
      }
      console.log('reconnectDb ok ' + name);
      dbObj.conn = conn;
    } finally {
    }
    await app.sleep(1000 * 3);
  } catch (err) {

  }
}

async function internalDbConn(app, name, method, ...args) {
  try {
    const conn = await internalCreateConn(app, name);
    const ret = await conn[method](...args);
    if (ret.err) {
      await reconnectDb(app, name, conn);
      return {
        'err': ret.err,
        'conn': null,
        'row': null,
        'rows': null
      };
    }
    return {
      'err': null,
      'conn': null,
      'row': ret.hasOwnProperty('row') ? ret['row'] : null,
      'rows': ret.hasOwnProperty('rows') ? ret['rows'] : null,
    };
  } catch (err) {
      return {
        'err': err,
        'conn': null,
        'row': null,
        'rows': null
      };
  };
}

async function execBcEventConn(app, method, ...args) {
  return await internalDbConn(app, constant.BCEVENTDB_NAME, method, ...args);
}

async function execBcNftConn(app, method, ...args) {
  return await internalDbConn(app, constant.BCNFTDB_NAME, method, ...args);
}

async function execGameConn(app, method, ...args) {
  return await internalDbConn(app, constant.GAMEDB_NAME, method, ...args);
}

exports.execBcEventConn = execBcEventConn;
exports.execBcNftConn = execBcNftConn;
exports.execGameConn = execGameConn;
